const { User, Role, Menu } = require('../models/Middle')
const { Op } = require('sequelize')
const crypto = require('crypto')  // 加密
const moment = require('moment')
const seq = require('../utils/seq')
const { getMenuTree } = require('./menu')
const { uploadImg } = require('../utils/util')

// 删除要注意是否要删除中间表的数据

// 注册用户(默认角色是普通用户，后续可以更改角色)
async function register (data) {
  data.ctime = moment().format('YYYY-MM-DD HH:mm:ss')
  data.mtime = moment().format('YYYY-MM-DD HH:mm:ss')
  try {
    // md5 加密
    let md5 = crypto.createHash('md5') // md5 加密
    data.password = md5.update(data.password).digest('hex')
    const user = await User.create(data)
    const roles = await Role.findAll({
      where: { id: "2c7d3dbe-5341-4cb2-be29-508065f64c50" }
    })
    return await user.addRoles(roles)
  } catch (error) {
    throw error
  }
}

// 根据用户名和密码查询（登录之前判断用户名和密码是否存在并正确）
async function findByNameAndPwd (data) {
  try {
    let md5 = crypto.createHash('md5') // md5 加密
    data.password = md5.update(data.password).digest('hex')
    return await User.findOne({
      where: {
        username: data.username,
        password: data.password
      }
    })
  } catch (error) {
    throw error
  }
}

// 重置（修改）密码（管理员重置才能各个用户的密码）
async function resetPwd (data) {
  try {
    // md5 加密
    let md5 = crypto.createHash('md5') // md5 加密
    data.password = md5.update(data.password).digest('hex')
    return await User.update({
      password: data.password
    }, {
      where: {
        id: data.id
      }
    })
  } catch (error) {
    throw error
  }
}

// 验证输入旧密码与数据库旧密码是否相等
async function pwdIseq (oldPwd, inputPwd) {
  let md5 = crypto.createHash('md5')
  inputPwd = md5.update(inputPwd).digest('hex')
  if (oldPwd === inputPwd) return true
  return false
}

// 修改用户头像
async function updateImg (origin, file, id) {
  try {
    const avatar = uploadImg(origin, file, id)
    return await User.update({
      avatar
    }, {
      where: {
        id
      }
    })
  } catch (error) {
    throw error
  }
}

// 查询（分页、排序、模糊查询搜索、查询状态）
/**
 * limit 提取多少行，offset 跳过多少行
 * @param {*} page 当前页码
 * @param {*} size 每页条数
 */
async function findAll (query) {
  try {
    const size = query.size ? parseInt(query.size) : 10 // 如果没传参数设置一个默认值
    const page = query.page ? parseInt(query.page) : 1
    const { count, rows } = await User.findAndCountAll({
      where: {
        status: {
          [Op.like]: query.status ? `%${JSON.parse(query.status) ? 1 : 0}%` : '%%' // 查询状态
        },
        [Op.or]: [ // 模糊查询
          { username: { [Op.like]: query.search ? `%${query.search}%` : '%%' } },
          { phone: { [Op.like]: query.search ? `%${query.search}%` : '%%' } },
          { gender: { [Op.like]: query.search ? `%${query.search}%` : '%%' } },
          { email: { [Op.like]: query.search ? `%${query.search}%` : '%%' } },
          { remark: { [Op.like]: query.search ? `%${query.search}%` : '%%' } },
          { ctime: { [Op.like]: query.search ? `%${query.search}%` : '%%' } },
          { mtime: { [Op.like]: query.search ? `%${query.search}%` : '%%' } }
        ],
      },
      include: [{
        model: Role,
        as: 'ur'
      }],
      offset: (page - 1) * size,
      limit: size,
      distinct: true, // 避免分页出的总数和实际数不匹配
      order: [
        [query.order ? query.order : 'ctime', query.sort ? query.sort : 'desc'] // 使用 Element 表格中的排序是互斥的，所以每次排序只能排一个元素的
      ]
    })
    return {
      count,
      data: rows
    }
  } catch (error) {
    throw error
  }
}

// 修改（考虑修改用户的角色问题）
async function update (data) {
  data['user'].mtime = moment().format('YYYY-MM-DD HH:mm:ss')
  try {
    const flag = await User.update(data['user'], {
      where: {
        id: data['user'].id
      }
    })
    if (flag == 1 && data['roleIds']) {
      const user = await User.findOne({
        where: { id: data['user'].id }
      })
      const roles = await Role.findAll({
        where: { id: data['roleIds'] }
      })
      return await user.setUr(roles)
    } else {
      return flag
    }
  } catch (error) {
    throw error
  }
}

// 删除（注意管理员不能删除，可以删除普通用户等）
// 删除用户：删除用户关联的所有表记录 user_role；删除用户记录
async function deleteById (id) {
  try {
    await seq.query(`delete from user_role where userId='${id}'`)
    return await User.destroy({
      where: {
        id
      }
    })
  } catch (error) {
    throw error
  }
}


// 根据id查询
async function findOneById (id) {
  try {
    const user = await User.findOne({
      where: {
        id
      },
      include: {
        model: Role,
        as: 'ur'
      }
    })
    return user
  } catch (error) {
    throw error
  }
}

// 根据用户名查询
async function findByName (username) {
  try {
    const user = await User.findOne({
      where: {
        username
      }
    })
    if (user === null) return false
    return true
  } catch (error) {
    throw error
  }
}

// 新增用户(考虑新增用户角色的问题)
async function add (data) {
  data['user'].ctime = moment().format('YYYY-MM-DD HH:mm:ss')
  data['user'].mtime = moment().format('YYYY-MM-DD HH:mm:ss')
  data['user'].password = crypto.createHash('md5').update('111111').digest('hex')
  try {
    const user = await User.create(data['user'])
    const roles = await Role.findAll({
      where: { id: data['role'] }
    })
    return await user.addUr(roles)
  } catch (error) {
    throw error
  }
}

/**
 * 用户下菜单
 * @param {*} id 
 */
async function findUserMenu (id) {
  try {
    const user = (await User.findOne({
      where: {
        id
      },
      include: [
        { // 用户角色
          model: Role,
          as: 'ur',
          through: { attributes: [] },
          include: [ // 角色菜单
            {
              model: Menu,
              as: 'menus',
              through: { attributes: [] },
              include: [
                {
                  model: Menu,
                  as: 'children',
                  include: [
                    {
                      model: Menu,
                      as: 'children'
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    })).toJSON()
    let menuIds = []
    user.ur.forEach(item => {
      item.menus.forEach(subItem => {
        menuIds.push(subItem.id)
      })
    })
    return getMenuTree(menuIds)
  } catch (error) {
    throw error
  }
}


module.exports = {
  register,
  findByNameAndPwd,
  resetPwd,
  updateImg,
  pwdIseq,
  findAll,
  update,
  deleteById,
  findOneById,
  findByName,
  add,
  findUserMenu
}